package simmar.xcs;

import ch.idsia.agents.Agent;
import ch.idsia.benchmark.mario.engine.GlobalOptions;
import ch.idsia.benchmark.mario.environments.Environment;
import ch.idsia.benchmark.mario.environments.MarioEnvironment;
import ch.idsia.benchmark.tasks.Task;
import ch.idsia.tools.EvaluationInfo;
import ch.idsia.tools.MarioAIOptions;
import ch.idsia.utils.statistics.StatisticalSummary;

import java.util.Vector;

import simmar.utilities.Logger;

public class XCSBasicTask implements Task, XCSConfig
{
    protected final static Environment environment = MarioEnvironment.getInstance();
    protected XCSAgent agent;
    protected MarioAIOptions options;
    protected String name = getClass().getSimpleName();
    protected EvaluationInfo evaluationInfo;
    protected Vector<StatisticalSummary> statistics = new Vector<StatisticalSummary>();
    protected float _previousDistancePassed;
    protected float _currentDistancePassed;

    /**
     * @param marioAIOptions
     */
    public XCSBasicTask(MarioAIOptions marioAIOptions)
    {
        this.setOptionsAndReset(marioAIOptions);
        _previousDistancePassed = 0.0f;
        _currentDistancePassed = 0.0f;
    }
    
    /**
     *
     * @param repetitionsOfSingleEpisode
     * @return
     */
    public void runSingleEpisode(final int repetitionsOfSingleEpisode)
    {
        for (int r = 0; r < repetitionsOfSingleEpisode; ++r)
        {
            this.reset();
            
            while (!environment.isLevelFinished())
            {
                environment.tick();
                
                if (!GlobalOptions.isGameplayStopped)
                {
                    if (XCS_DEBUG_LEVEL.compareTo(DEBUG_LEVEL.NORMAL) > 0)
                        Logger.logLine("------------------------------------------------------------- Task loop -------------------------------------------------------------");
                    
                    agent.integrateObservation(environment);
                    agent.giveIntermediateReward(0);
                    boolean[] action = agent.getAction();
                    environment.performAction(action);
                }
            }
            
            Logger.logLine("Level finished");
            
            environment.closeRecorder(); // recorder initialized in
                                         // environment.reset
            environment.getEvaluationInfo().setTaskName(name);
            this.evaluationInfo = environment.getEvaluationInfo().clone();
        }
    }

    public void setOptionsAndReset(MarioAIOptions options)
    {
        this.options = options;
        reset();
    }

    public void setOptionsAndReset(final String options)
    {
        this.options.setArgs(options);
        reset();
    }

    public void doEpisodes(int amount, boolean verbose, final int repetitions)
    {
        for (int j = 0; j < EvaluationInfo.numberOfElements; j++)
        {
            statistics.addElement(new StatisticalSummary());
        }
        
        for (int i = 0; i < amount; ++i)
        {
            this.reset();
            this.runSingleEpisode(repetitions);
            if (verbose)
                System.out.println(environment.getEvaluationInfoAsString());

            for (int j = 0; j < EvaluationInfo.numberOfElements; j++)
            {
                statistics.get(j).add(environment.getEvaluationInfoAsInts()[j]);
            }
        }

        System.out.println(statistics.get(3).toString());
    }

    public boolean isFinished()
    {
        return false;
    }

    public void reset()
    {
        agent = (XCSAgent)options.getAgent();
        environment.reset(options);
        agent.reset();
        agent.setObservationDetails(environment.getReceptiveFieldWidth(), environment.getReceptiveFieldHeight(), environment.getMarioEgoPos()[0], environment.getMarioEgoPos()[1]);
    }

    public String getName()
    {
        return name;
    }

    public void printStatistics()
    {
        System.out.println(evaluationInfo.toString());
    }

    public EvaluationInfo getEvaluationInfo()
    {
        // System.out.println("evaluationInfo = " + evaluationInfo);
        return evaluationInfo;
    }

    @Override
    public int evaluate(Agent controller)
    {
        // TODO Auto-generated method stub
        return 0;
    }
}